<template>
  <div class="file-upload">
      <div class="file-upload-container" @click.prevent="triggerUpload" v-bind="$attrs">
          <slot v-if="fileStatus === 'loading'" name="loading">
              <button class="btn btn-primary" disabled>正在上传...</button>
          </slot>
          <slot v-else-if="fileStatus === 'sucess'" name='uploaded' :uploadData="uploadData">
              <button class="btn btn-primary">上传成功</button>
          </slot>
          <slot v-else-if="fileStatus === 'error'" name='error'>
              <button class="btn btn-primary" >上传失败</button>
          </slot>
         
          <slot v-else name="default">
              <button class="btn btn-primary">上传文件</button>
          </slot>
          </div>
      <input type="file"
       class="file-input d-none"
       ref="fileInput"
       @change="handleFileChange">
  </div>
</template>

<script lang='ts'>
/* 上传文件，自定义样式 */
import {defineComponent,ref,PropType,watch} from 'vue'

import axios from '@/api/request'

// 定义上传的状态
type UploaderStatus = 'ready' | 'loading' | 'sucess' | 'error'

// 自定义检查，是一个函数，返回的是布尔值
type checkFunction = (file: File) => boolean

export default defineComponent({
props: {
    action: {
        type:String,
        required: true
    },
    /* 上传前的一系列检查 */
    boforeUpload: {
        type: Function as PropType<checkFunction>
    },
    /* 修改是图片的回显 */
    uploaded: {
        type: Object
    }
},
inheritAttrs: false, //自定义样式或者属性不添加在根标签上
// 定义要暴露的上传成功事件，上传失败事件
emits: ['file-uploaded','file-uploaded-error'],
setup(props,context){
    console.log('11',props.uploaded);


    // 绑定ref,获得input元素的节点
    const fileInput = ref<null | HTMLInputElement>(null)

    

    
    // 创建上传状态的响应式对象
    const fileStatus = ref<UploaderStatus>(props.uploaded?'sucess':'ready')

    // 定义返回出去的数据
    const uploadData = ref(props.uploaded) // 同步获取的时候

    watch(()=> props.uploaded,(newVal)=> {
        if (newVal) {
            fileStatus.value = 'sucess'
            uploadData.value = newVal
        }
    })

    const triggerUpload  = () => {
        //当input节点存在的时候，就触发点击事件
        if (fileInput.value) {
           fileInput.value.click() 
        }
    }

    // input 的change事件
    const handleFileChange = ((e:Event) => {
        // 获取里面的文件,这样是为了获得file属性
        const currentTarget = e.target as HTMLInputElement
        // 如果条件为真，说明已经选择了文件，可以上传
        if (currentTarget.files) {
            // 因为currentTarget.files不是一个数组，需要手动转换
            const fiels = Array.from(currentTarget.files)

            // 如果存在该属性，就做上传前的一系列检查
            if (props.boforeUpload) {
                const result = props.boforeUpload(fiels[0])

                // 如果不满足条件，就不执行下面的程序
                if (!result) {
                    return
                }
            }
            fileStatus.value = 'loading'
            const formData = new FormData
            
            formData.append('file',fiels[0])
            axios.post(props.action ,formData,{
                headers: {
                    'Content-Type': 'multipart/form-data'
                }
            }).then(res => {
                fileStatus.value = 'sucess'
                // 上传成功后，暴露成功事件
                uploadData.value = res.data
                context.emit('file-uploaded',res.data)
                
            }).catch(err => {
                fileStatus.value = 'error'
                context.emit('file-uploaded-error',{err})
            }).finally(() => {
                if (fileInput.value) {
                    fileInput.value.value = ''
                }
            })

        }
    })


    return {
        fileInput,
        triggerUpload,
        handleFileChange,
        fileStatus,
        uploadData
    }
}
})
</script>

<style>

</style>